#include "HardDisk.h"

STATIC CONST WORD wPort[] = {0x1F2, 0x172};

void DevHardDiskRead(BYTE bNo, DWORD dwLBAAddress, BYTE bReadNumber,
                     LPVOID lpvBuffer) {
  __asm__("out %%al,%%dx\n"
          "inc %%dx\n"
          "mov %4,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "and $0x0F,%%al\n"
          "or %%bl,%%al\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "mov $0x20,%%al\n"
          "out %%al,%%dx\n"
          "1:"
          "nop\n"
          "in %%dx,%%al\n"
          "and $0x88,%%al\n"
          "cmp $0x08,%%al\n"
          "jnz 1b\n"
          "sub $7,%%dx\n"
          "rep insw\n" ::"a"(bReadNumber),
          "c"((DWORD)bReadNumber << 8), "d"(wPort[bNo >> 1]), "D"(lpvBuffer),
          "m"(dwLBAAddress), "b"((BYTE)(((bNo & 1) << 4) | 0xE0)));
}

void DevHardDiskWrite(BYTE bNo, DWORD dwLBAAddress, BYTE bWriteNumber,
                      LPVOID lpvBuffer) {
  __asm__("out %%al,%%dx\n"
          "inc %%dx\n"
          "mov %4,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "and $0x0F,%%al\n"
          "or %%bl,%%al\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "mov $0x30,%%al\n"
          "out %%al,%%dx\n"
          "1:"
          "nop\n"
          "in %%dx,%%al\n"
          "and $0x88,%%al\n"
          "cmp $0x08,%%al\n"
          "jnz 1b\n"
          "sub $7,%%dx\n"
          "rep outsw\n" ::"a"(bWriteNumber),
          "c"((DWORD)bWriteNumber << 8), "d"(wPort[bNo >> 1]), "S"(lpvBuffer),
          "m"(dwLBAAddress), "b"((BYTE)(((bNo & 1) << 4) | 0xE0)));
}

BOOLEAN DevHardDiskExisted(BYTE bNo, DWORD dwLBAAddress) {
  register BOOLEAN ret = FALSE;
  __asm__("out %%al,%%dx\n"
          "inc %%dx\n"
          "mov %5,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "shr $8,%%eax\n"
          "and $0x0F,%%al\n"
          "or %%bl,%%al\n"
          "out %%al,%%dx\n"
          "inc %%dx\n"
          "mov $0x20,%%al\n"
          "out %%al,%%dx\n"
          "1:"
          "nop\n"
          "in %%dx,%%al\n"
          "test $1,%%al\n"
          "jnz 1f\n"
          "and $0x88,%%al\n"
          "cmp $0x08,%%al\n"
          "jnz 1b\n"
          "sub $7,%%dx\n"
          "2:"
          "in %%dx,%%ax\n"
          "loop 2b\n"
          "mov $1,%0\n"
          "1:"
          : "=r"(ret)
          : "a"(1), "b"((BYTE)(((bNo & 1) << 4) | 0xE0)), "c"(0x100),
            "d"(wPort[bNo >> 1]), "m"(dwLBAAddress));
  return ret;
}
